package com.controller.common;

import com.config.PropertiesInfo;
import com.entity.common.ApiResult;
import com.entity.common.TableInfo;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.service.common.TableInfoService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.exception.InvalidConfigurationException;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by  qdf on 2019/3/8.
 */
@RestController
public class GenerateCodeController {

    @Autowired
    private TableInfoService tableInfoService;

    @Autowired
    private PropertiesInfo propertiesInfo;

    @RequestMapping("startGenerateCode")
    public  ApiResult StartGenerateCode(String packageName,String moduleName,String moduleNameChinese,String tableName,
                                String showField,String whereField,String formField){
        try {
            Gson gson=new Gson();
            List<TableInfo> showFieldList = gson.fromJson(showField,new TypeToken<ArrayList<TableInfo>>(){}.getType());
            List<TableInfo> whereFieldList = gson.fromJson(whereField,new TypeToken<ArrayList<TableInfo>>(){}.getType());
            List<TableInfo> formFieldList = gson.fromJson(formField,new TypeToken<ArrayList<TableInfo>>(){}.getType());
            if(showFieldList.isEmpty()||showFieldList.size()<0){
                return new ApiResult(false,"显示字段不能没有呀！");
            }
            if(formFieldList.isEmpty()||formFieldList.size()<0){
                return new ApiResult(false,"表单录入字段不能没有呀！");
            }
            if(StringUtils.isBlank(packageName)||StringUtils.isBlank(moduleName)||StringUtils.isBlank(moduleNameChinese)||StringUtils.isBlank(tableName)){
                return new ApiResult(false,"包名 模块名 表名 不能为空呀！");
            }
            return generateCode(packageName, moduleName, moduleNameChinese, tableName, showFieldList, whereFieldList, formFieldList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return new ApiResult(false,"生成失败!");
    }


    public static void main(String[] args) {
        try {
/*
            insert("E:\\\\work\\\\core\\\\src\\\\main\\\\java\\\\com\\\\dao\\\\xsxt\\\\Dao.ftl",60,"@Mapper\n" +
                    "@Repository\r");*/

         /*   RandomAccessFile raf = new RandomAccessFile("E:\\work\\core\\src\\main\\java\\com\\dao\\xsxt\\Dao.ftl", "rw");
            raf.seek(raf.length()-1);
            raf.write("\n    List<PrizeSet> getPageList(PrizeSet prizeSet);\n}".getBytes());
            raf.seek(60);
            raf.write("@Mapper\n@Repository\npublic interface PrizeSetMapper{\n".getBytes());*/
          /*  RandomAccessFile raf = new RandomAccessFile("E:\\work\\core\\src\\main\\java\\com\\dao\\xsxt\\Dao.ftl", "rw");
            int targetLineNum = 2;
            int currentLineNum = 0;*/
            /*while(raf.readLine() != null){
                System.out.println(raf.readLine());
                if(currentLineNum == targetLineNum){ // 定位到目标行时结束
                    break;
                }
                currentLineNum++;
            }*/
           /* raf.seek(0);*/
            /*System.out.println(raf.get;*/
          /* for(int i=0;i<6;i++){
               if(i==3){
                   break;
               }
           }
*/
         /* raf.seek(raf.length()-1);
           raf.write("@Mapper".getBytes());*/
        /* for(int i=0;i<raf.length();i++){
             if(i==3){
                *//* raf.seek(4);*//*
                 raf.write(("@Mapper"+raf.readLine()).getBytes());
                 break;
             }
             //System.out.println("第"+i+"行"+raf.readLine());
         }
          raf.close();*/
/*;*/
            /*GenerateCodeController generateCodeController = new GenerateCodeController();
            generateCodeController.generateCode();*/
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * qdf
     * @param packageName  包名
     * @param moduleName 模块名 英文
     * @param moduleNameChinese 模块名 中文
     * @param tableName 表名
     * @param showField 列表需要展示的字段
     * @param whereField 需要做为条件字段
     * @param formField  表单需要填写的字段
     * @return
     * @throws Exception
     */
    public ApiResult generateCode(String packageName,String moduleName,String moduleNameChinese,String tableName,
                                  List<TableInfo> showField,List<TableInfo> whereField,List<TableInfo> formField) throws Exception {
        System.out.println(Thread.currentThread() .getStackTrace()[1].getMethodName());
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
        cfg.setDirectoryForTemplateLoading(new File( GenerateCodeController.class.getResource("/templates").getPath()));
        cfg.setDefaultEncoding("UTF-8");
        String path = System.getProperty("user.dir")+"\\src";
        Writer out = null;
        Template template=null;
        try {
             packageName=packageName.replace(".","/");
            String [] attr={"controller","service"};//禁止修改
            // 1.生成Controller Service
            for(String item:attr){
                template = cfg.getTemplate(indexUpperCase(item)+".ftl");
                File file =handleFile(path+"/main/java/com/"+item+"/"+packageName+"/"+indexUpperCase(moduleName)+indexUpperCase(item)+".java");
                Map<String, Object> root = new HashMap<>();
                root.put("createDate",new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
                root.put("packageName",packageName);
                root.put("moduleName",moduleName);// 模块名
                out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
                template.process(root, out);
            }
            //2.生成页面
            path = System.getProperty("user.dir")+"\\src\\main\\webapp\\admin\\"+packageName+"\\"+moduleName+".jsp";
            template = cfg.getTemplate("Page.ftl");
            File file = handleFile(path);
            Map<String, Object> root = new HashMap<>();
            root.put("createDate",new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
            root.put("packageName",packageName);
            root.put("moduleName",moduleName);
            root.put("moduleNameChinese",moduleNameChinese);
            root.put("contextPath","${pageContext.request.contextPath}");

            //列表需要展示的字段
            /*List<TableInfo> showField=new ArrayList<>();
            showField.add(new TableInfo("name","姓名"));
            showField.add(new TableInfo("age","年龄"));
*/
            //需要做为查询条件的字段
           /* List<TableInfo> whereField=new ArrayList<>();
            whereData.add(new TableInfo("name","姓名"));*/

            root.put("fieldList",showField);
            root.put("whereData",whereField);
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            template.process(root, out);


            /**
             * 生成输入表单
             */
            /*List<TableInfo> formData=new ArrayList<>();

            formData.add(new TableInfo("name","姓名"));
            formData.add(new TableInfo("age","年龄"));*/

            root.put("formData",formField);
            path = System.getProperty("user.dir")+"\\src\\main\\webapp\\admin\\"+packageName+"\\"+moduleName+"Form.jsp";
            template = cfg.getTemplate("PageForm.ftl");
            file = handleFile(path);
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            template.process(root, out);

            /**
             * 更新generatorConfig.xml
             */
           /* Map<String, Object> druid = propertiesInfo.getDatasource().get("druid");
            root.put("url",druid.get("url").toString());
            root.put("username",druid.get("username").toString());
            root.put("password",druid.get("password").toString());
            root.put("driver-class-name",druid.get("driver-class-name").toString());
            root.put("tableName",tableName);*/

            root.put("url","jdbc:mysql://192.168.0.177:3306/school_system?characterEncoding=utf8");
            root.put("username","root");
            root.put("password","123456");
            root.put("driverClassName","com.mysql.jdbc.Driver");
            root.put("tableName",tableName);
            root.put("targetPackage",packageName.replace("/","."));

            template = cfg.getTemplate("generatorConfig.ftl");
            path= System.getProperty("user.dir")+"\\src\\main\\resources\\generatorConfig.xml";
            file = handleFile(path);
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            template.process(root, out);

            List<String> warnings = new ArrayList<>();
            InputStream is = new FileInputStream(new File(path));
            ConfigurationParser cp = new ConfigurationParser(warnings);
            org.mybatis.generator.config.Configuration config = null;

            config = cp.parseConfiguration(is);
            DefaultShellCallback callback = new DefaultShellCallback(true);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);

            //生成DAO
            template = cfg.getTemplate("Dao.ftl");
            path= System.getProperty("user.dir")+"/src/main/java/com/dao/"+packageName+"/"+indexUpperCase(moduleName)+"Mapper.java";
            file = handleFile(path);
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            template.process(root, out);

            //xml追加分页方法
            RandomAccessFile raf = new RandomAccessFile(System.getProperty("user.dir")+"/src/main/resources/mapper/"+packageName+"/"+indexUpperCase(moduleName)+"Mapper.xml", "rw");
            raf.seek(raf.length()-9);
            raf.write(("    <select id=\"getPageList\" resultMap=\"BaseResultMap\">\n" +
                    "      select\n" +
                    "      <include refid=\"Base_Column_List\" />\n" +
                    "      from "+tableName+"\n" +
                    "    </select>\n</mapper>").getBytes());
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }
        return new ApiResult(true,"生成成功， 请检查生成是否无误！");
    }

    /**
     * 生成代码
     * @return
     */
/*    public ApiResult generateCode() throws Exception {
        System.out.println(Thread.currentThread() .getStackTrace()[1].getMethodName());
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
        cfg.setDirectoryForTemplateLoading(new File( GenerateCodeController.class.getResource("/templates").getPath()));
        cfg.setDefaultEncoding("UTF-8");
        String path = System.getProperty("user.dir")+"\\src";
        Writer out = null;
        Template template=null;
        try {
            String packageName="xsxt".replace(".","/");
            String moduleName="test";
            String moduleNameChinese="测试";
            String tableName="test";
            String [] attr={"controller","service"};//禁止修改
            // 1.生成Controller Service
            for(String item:attr){
                template = cfg.getTemplate(indexUpperCase(item)+".ftl");
                File file =handleFile(path+"/main/java/com/"+item+"/"+packageName+"/"+indexUpperCase(moduleName)+indexUpperCase(item)+".java");
                Map<String, Object> root = new HashMap<>();
                root.put("createDate",new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
                root.put("packageName",packageName);
                root.put("moduleName",moduleName);// 模块名
                out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
                template.process(root, out);
            }
             //2.生成页面
            path = System.getProperty("user.dir")+"\\src\\main\\webapp\\admin\\"+packageName+"\\"+moduleName+".jsp";
            template = cfg.getTemplate("Page.ftl");
            File file = handleFile(path);
            Map<String, Object> root = new HashMap<>();
            root.put("createDate",new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
            root.put("packageName",packageName);
            root.put("moduleName",moduleName);
            root.put("moduleNameChinese",moduleNameChinese);
            root.put("contextPath","${pageContext.request.contextPath}");

            //列表需要展示的字段
            List<TableInfo> list=new ArrayList<>();
            list.add(new TableInfo("name","姓名"));
            list.add(new TableInfo("age","年龄"));

            //需要做为查询条件的字段
            List<TableInfo> whereData=new ArrayList<>();
            whereData.add(new TableInfo("name","姓名"));

            root.put("fieldList",list);
            root.put("whereData",whereData);
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            template.process(root, out);


            *//**
             * 生成输入表单
             *//*
            List<TableInfo> formData=new ArrayList<>();

            formData.add(new TableInfo("name","姓名"));
            formData.add(new TableInfo("age","年龄"));

            root.put("formData",formData);
            path = System.getProperty("user.dir")+"\\src\\main\\webapp\\admin\\"+packageName+"\\"+moduleName+"Form.jsp";
            template = cfg.getTemplate("PageForm.ftl");
            file = handleFile(path);
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            template.process(root, out);

            *//**
             * 更新generatorConfig.xml
             *//*
           *//* Map<String, Object> druid = propertiesInfo.getDatasource().get("druid");
            root.put("url",druid.get("url").toString());
            root.put("username",druid.get("username").toString());
            root.put("password",druid.get("password").toString());
            root.put("driver-class-name",druid.get("driver-class-name").toString());
            root.put("tableName",tableName);*//*

            root.put("url","jdbc:mysql://192.168.0.177:3306/school_system?characterEncoding=utf8");
            root.put("username","root");
            root.put("password","123456");
            root.put("driverClassName","com.mysql.jdbc.Driver");
            root.put("tableName",tableName);
            root.put("targetPackage",packageName.replace("/","."));

            template = cfg.getTemplate("generatorConfig.ftl");
            path= System.getProperty("user.dir")+"\\src\\main\\resources\\generatorConfig.xml";
            file = handleFile(path);
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            template.process(root, out);

            List<String> warnings = new ArrayList<>();
            InputStream is = new FileInputStream(new File(path));
            ConfigurationParser cp = new ConfigurationParser(warnings);
            org.mybatis.generator.config.Configuration config = null;

            config = cp.parseConfiguration(is);
            DefaultShellCallback callback = new DefaultShellCallback(true);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);

            //生成DAO
            template = cfg.getTemplate("Dao.ftl");
            path= System.getProperty("user.dir")+"/src/main/java/com/dao/"+packageName+"/"+indexUpperCase(moduleName)+"Mapper.java";
            file = handleFile(path);
            out = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
            template.process(root, out);

            //xml追加分页方法
            RandomAccessFile raf = new RandomAccessFile(System.getProperty("user.dir")+"/src/main/resources/mapper/"+packageName+"/"+indexUpperCase(moduleName)+"Mapper.xml", "rw");
            raf.seek(raf.length()-9);
            raf.write(("    <select id=\"getPageList\" resultMap=\"BaseResultMap\">\n" +
                    "      select\n" +
                    "      <include refid=\"Base_Column_List\" />\n" +
                    "      from "+tableName+"\n" +
                    "    </select>\n</mapper>").getBytes());
        } catch (IOException | TemplateException e) {
            e.printStackTrace();
        }
        return new ApiResult(true,"生成成功， 请检查生成是否无误！");
    }*/

    private File  handleFile(String path) throws IOException {
        File f = new File(path);
        if(f.exists()){
           if(f.delete()){
               System.out.println(">> 删除已存在文件！");
           }
        }
        if (!f.getParentFile().exists()) {
            if (!f.getParentFile().mkdir()){
                System.out.println(">> 创建目录");
            }
        }
        if (f.createNewFile()){
            System.out.println(">> 创建文件成功！");
        }
        return  f;
    }

    @RequestMapping("getTableInfo")
    public List<TableInfo> getTableInfo(){
        return tableInfoService.getTableInfo();
    }

    @RequestMapping("getColumnInfo")
    public List<TableInfo> getColumnInfo(String tableName){
        return tableInfoService.getColumnInfo(tableName);
    }

    private static String indexUpperCase(String str){
        return  str.substring(0,1).toUpperCase()+str.substring(1,str.length());
    }
    public static void insert(String fileName,long pos,String insertContent)throws IOException{
        RandomAccessFile raf=null;
        //创建一个临时文件来保存插入点后的数据
        File tmp=File.createTempFile("tmp", null);
        FileOutputStream tmpOut=null;
        FileInputStream tmpIn=null;
        tmp.deleteOnExit();
        try{
            raf=new RandomAccessFile(fileName,"rw");
            tmpOut=new FileOutputStream(tmp);
            tmpIn=new FileInputStream(tmp);
            raf.seek(pos);
            //下面代码将插入点后的内容读入临时文件中保存
            byte[] bbuf=new byte[64];
            //用于保存实际读取的字节数
            int hasRead=0;
            //使用循环方式读取插入点后的数据
            while((hasRead=raf.read(bbuf))>0){
                //将读取的数据写入临时文件
                tmpOut.write(bbuf,0,hasRead);
            }
            //下面代码插入内容
            //把文件记录指针重新定位到pos位置
            raf.seek(pos);
            //追加需要插入的内容
            raf.write(insertContent.getBytes());
            //追加临时文件中的内容
            while((hasRead=tmpIn.read(bbuf))>0){
                raf.write(bbuf,0,hasRead);
            }
        }
        catch (Exception e){
            e.printStackTrace();
        }
        finally{
            if (raf != null) {
                raf.close();
            }
        }
    }

}

